package com.jiguang.Electricvehicle.ble;

import android.app.Application;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.content.Context;
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.text.TextUtils;
import android.util.Log;

import com.clj.fastble.BleManager;
import com.clj.fastble.BuildConfig;
import com.clj.fastble.bluetooth.BleBluetooth;
import com.clj.fastble.bluetooth.MultipleBluetoothController;
import com.clj.fastble.callback.BleGattCallback;
import com.clj.fastble.callback.BleNotifyCallback;
import com.clj.fastble.callback.BleScanCallback;
import com.clj.fastble.callback.BleWriteCallback;
import com.clj.fastble.data.BleDevice;
import com.clj.fastble.exception.BleException;
import com.clj.fastble.scan.BleScanRuleConfig;
import com.clj.fastble.scan.BleScanner;

import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import java.util.Set;

/**
 * 国际Json版本
 */
public class InternationalBLEManager {
    static final String SERVICE_UUID = "0000ff00-0000-1000-8000-00805f9b34fb";
    static final String CHARACTER_WRITE_UUID = "0000ff01-0000-1000-8000-00805f9b34fb";
    static final String CHARACTER_READ_UUID = "0000ff04-0000-1000-8000-00805f9b34fb";
    static final String CHARACTER_NOTIFY_UUID = "0000ff02-0000-1000-8000-00805f9b34fb";
    public static final String TAG = "BLEManager";
    private boolean isConnected;
    private boolean isConnecting;
    private BleDevice mBleDevice;
    private static InternationalBLEManager instance;
    private Queue<byte[]> queue = new LinkedList<>();
    private IBleCallback callback;

    public void setCallback(IBleCallback callback) {
        this.callback = callback;
    }

    public InternationalBLEManager() {
        //sona注释
    }

    public static InternationalBLEManager getInstance() {
        synchronized (InternationalBLEManager.class) {
            if (instance == null) {
                instance = new InternationalBLEManager();
            }
        }
        return instance;
    }

    /**
     * 初始化
     */
    public void initBle() {
        Application mApplication = null;
        try {
            mApplication = (Application) Class.forName("android.app.ActivityThread").getMethod("currentApplication").invoke(null, (Object[]) null);
        } catch (Exception e) {
            e.printStackTrace();
        }
        BleManager.getInstance().init(mApplication);
        BleManager.getInstance()
                .enableLog(BuildConfig.DEBUG)
                .setConnectOverTime(5 * 1000);
    }

    /**
     * 蓝牙是否已链接
     */
    public boolean isBleConnected() {
        return mBleDevice == null ? false : BleManager.getInstance().isConnected(mBleDevice);
    }

    /**
     * 蓝牙是否已链接
     */
    public void cancelScan() {
        try {
            BleManager.getInstance().cancelScan();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 蓝牙是否已链接
     */
    public boolean isBleConnected(String mac) {
        if (BleManager.getInstance().getAllConnectedDevice() == null) {
            return false;
        }
        if (BleManager.getInstance().getAllConnectedDevice().size() > 0 && BleManager.getInstance().isConnected(mac)) {
            return true;
        }
        return false;
    }


    /**
     * 扫描到首个符合扫描规则的设备后，便停止扫描，然后连接该设备。
     *
     * @param stubId
     * @param mac    可选
     */
    public void scanAndConnect(String stubId, String mac, IBleCallback iBleCallback) {
        Log.d(TAG, "-----mac-----" + mac);
        this.callback = iBleCallback;
        BluetoothDevice bleDevice = getConnectedBleDevice(null, mac);
        if (bleDevice != null) {
            BleDevice scanResult = new BleDevice(bleDevice);
            new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
                @Override
                public void run() {
                    connect(scanResult);
                }
            }, 100);
            return;
        }

        BleScanRuleConfig scanRuleConfig = new BleScanRuleConfig.Builder()
//                .setDeviceName(true, stubId)         // 只扫描指定广播名的设备，可选
                .setDeviceMac(mac)                  // 只扫描指定mac的设备，可选
                .setScanTimeOut(15 * 1000)              // 扫描超时时间，可选，默认10秒；小于等于0表示不限制扫描时间
//                .setAutoConnect(true)
                .build();
        BleManager.getInstance().initScanRule(scanRuleConfig);

        //扫描及过滤过程是在工作线程中进行，所以不会影响主线程的UI操作，但每一个回调结果都会回到主线程。 连接操作会在主线中进行。
        BleManager.getInstance().scan(new BleScanCallback() {
            @Override
            public void onScanFinished(List<BleDevice> bleDeviceList) {
                Log.d(TAG, "-----onScanFinished-----");
                BleDevice scanResult;
                if (bleDeviceList == null || bleDeviceList.size() < 1) {
                    scanResult = null;
                } else {
                    scanResult = bleDeviceList.get(0);
                    //解决重复问题
                    if (isConnectingDevice(scanResult)) {
                        return;
                    }
                    if (BleManager.getInstance().getMultipleBluetoothController().isContainDevice(scanResult)) {
                        return;
                    }
                    new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
                        @Override
                        public void run() {
                            connect(scanResult);
                        }
                    }, 100);
                }

                // 扫描结束，结果即为扫描到的第一个符合扫描规则的BLE设备，如果为空表示未搜索到（主线程）
                Log.d(TAG, "-----onScanFinished-----" + scanResult);
                if (scanResult == null) {
                    isConnecting = false;
                }
            }

            @Override
            public void onScanStarted(boolean success) {
                // 开始扫描（主线程）
                Log.d(TAG, "-----onScanStarted-----");
                isConnecting = true;
            }

            @Override
            public void onScanning(BleDevice bleDevice) {
                BleScanner.getInstance().stopLeScan();
            }
        });
    }

    /**
     * 是否正在连接中
     *
     * @param device
     * @return
     */
    private boolean isConnectingDevice(BleDevice device) {
        try {
            MultipleBluetoothController controller = BleManager.getInstance().getMultipleBluetoothController();
            if (controller == null) {
                return false;
            }
            Field bleTempHashMap = controller.getClass().getDeclaredField("bleTempHashMap");
            bleTempHashMap.setAccessible(true);
            HashMap<String, BleBluetooth> map = (HashMap<String, BleBluetooth>) bleTempHashMap.get(controller);
            return map.containsKey(device.getKey());
        } catch (Exception ex) {

        }
        return false;
    }

    public void connect(BleDevice bleDevice) {
        BleManager.getInstance().connect(bleDevice, mBleGattCallback);
    }

    private BleGattCallback mBleGattCallback = new BleGattCallback() {
        @Override
        public void onStartConnect() {
            // 开始连接
            Log.d(TAG, "-----onStartConnect-----");
            if (callback != null) {
                callback.onStartConnect();
            }
            isConnecting = true;
            clearBleManager();
        }

        @Override
        public void onConnectFail(BleDevice bleDevice, BleException exception) {
            // 连接失败
            Log.d(TAG, "-----onConnectFail-----" + exception.getCode() + ",cause-----" + exception.getDescription());
            if (callback != null) {
                callback.onConnectFail(bleDevice, exception);
            }
            isConnecting = false;
            clearBleManager();

        }

        @Override
        public void onConnectSuccess(BleDevice bleDevice, BluetoothGatt gatt, int status) {
            // 连接成功，BleDevice即为所连接的BLE设备
            Log.d(TAG, "-----onConnectSuccess-----");
            if (callback != null) {
                callback.onConnectSuccess(bleDevice, gatt, status);
            }
            isConnecting = false;
            mBleDevice = bleDevice;
            new Handler().postDelayed(() -> startNotify(bleDevice), 200);
        }

        @Override
        public void onDisConnected(boolean isActiveDisConnected, BleDevice device, BluetoothGatt gatt, int status) {
            // 连接中断，isActiveDisConnected表示是否是主动调用了断开连接方法
            Log.d(TAG, "-----onDisConnected-----");
            if (callback != null) {
                callback.onDisConnected(isActiveDisConnected, device, gatt, status);
            }
            //重启后连接不了问题处理
            if (gatt != null) {
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
                    gatt.close();
                }
            }
            isConnecting = false;

            clearBleManager();

        }
    };

    /**
     * 连接的系统蓝牙
     *
     * @param stubId
     * @param mac
     * @return
     */
    private BluetoothDevice getConnectedBleDevice(String stubId, String mac) {
//        if (TextUtils.isEmpty(stubId)) {
//            return null;
//        }
        BluetoothAdapter defaultAdapter = BluetoothAdapter.getDefaultAdapter();
        if (defaultAdapter != null) {
            Set<BluetoothDevice> bondedDevices = defaultAdapter.getBondedDevices();
            for (BluetoothDevice bondedDevice : bondedDevices) {
                String name = bondedDevice.getName();
                String address = bondedDevice.getAddress();
                boolean isConnect = false;
                try {
                    isConnect = (boolean) bondedDevice.getClass().getMethod("isConnected").invoke(bondedDevice);
                } catch (Exception ex) {

                }
                if (isConnect && !TextUtils.isEmpty(mac) && mac.equals(address)) {
                    return bondedDevice;
                }
//                if (isConnect && !TextUtils.isEmpty(name) && stubId.equals(name)) {
//                    return bondedDevice;
//                }
//                if (!TextUtils.isEmpty(mac) && !mac.equals(address)) {
//                    continue;
//                }
//                if (isConnect && stubId.equals(name)) {
//                    return bondedDevice;
//                }
            }
        }
        return null;
    }


    /**
     * 开始通知
     */
    public void startNotify(BleDevice device) {
        BleManager.getInstance().notify(device, SERVICE_UUID, CHARACTER_NOTIFY_UUID, new BleNotifyCallback() {
            @Override
            public void onNotifySuccess() {
                // 打开通知操作成功
                Log.d(TAG, "-----onNotifySuccess-----");
            }

            @Override
            public void onNotifyFailure(BleException exception) {
                // 打开通知操作失败
                Log.d(TAG, "-----onNotifyFailure-----" + exception.getDescription());
                disconnectAllDevice();
            }

            @Override
            public void onCharacteristicChanged(byte[] data) {
                // 打开通知后，设备发过来的数据将在这里出现
                if (callback != null) {
                    callback.onCharacteristicChanged(data);
                }
            }
        });
    }

    //添加队列
    public void addWriteQueue(byte[] data) {
        queue.offer(data);
    }


    /**
     * 写
     *
     * @param data
     */
    public void write(byte[] data) {
        BleManager.getInstance().write(mBleDevice, SERVICE_UUID, CHARACTER_WRITE_UUID, data, new BleWriteCallback() {
            @Override
            public void onWriteSuccess(int current, int total, byte[] justWrite) {
                Log.d(TAG, "-----WriteSuccess-----" + new String(justWrite));
            }

            @Override
            public void onWriteFailure(BleException exception) {
                Log.d(TAG, "-----WriteFailure-----" + exception.getDescription());
            }
        });
    }

    private void write() {
        //判断首个元素，但不移除
        if (queue.peek() == null) {
            return;
        }
        //取出,移除首个元素
        byte[] data = queue.poll();
        //true,true,300
        BleManager.getInstance().write(mBleDevice, SERVICE_UUID, CHARACTER_WRITE_UUID, data, new BleWriteCallback() {
            @Override
            public void onWriteSuccess(int current, int total, byte[] justWrite) {
                Log.d(TAG, "-----WriteSuccess-----aa" + justWrite.toString());
                if (current == total) {//表示一条命令已经写完
                    write();
                }
            }

            @Override
            public void onWriteFailure(BleException exception) {
                Log.d(TAG, "-----WriteFailure-----" + exception.getDescription());
            }
        });
    }

    /**
     * 断开所有设备
     */
    public void disconnectAllDevice() {
        clearBleManager();
        BleManager.getInstance().disconnectAllDevice();
    }

    /**
     * 重置 清空数据
     */
    private void clearBleManager() {
        mBleDevice = null;
        isConnecting = false;
    }

    public boolean isBlueEnable() {
        return BleManager.getInstance().isBlueEnable();
    }

    public void enableBluetooth() {
        BleManager.getInstance().enableBluetooth();
    }

}